package edu.odu.cs.sstore.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import edu.odu.cs.sstore.domain.User;
import edu.odu.cs.sstore.dto.UserDTO;
import edu.odu.cs.sstore.repository.AuthorityRepository;
import edu.odu.cs.sstore.repository.UserRepository;

@Service(value="userService")
public class UserServiceImpl implements UserService {
 
	@Autowired(required=true)
	private UserRepository userRepository;
 
	@Autowired(required=true)
	private AuthorityRepository authorityRepository;
	
	// TODO - only allow ROLE_ADMIN to do this
	@Transactional
	public UserDTO createUser(UserDTO user) {
		User u = new User();
		u.setId(user.getId());
		u.setUsername(user.getUsername());
		u.setName(user.getName());
		u.setPassword(user.getPassword());
		
		// reconcile the roles
		// remove old roles (if in current domain obj, but not in the DTO, then remove it)
		for(GrantedAuthority existing : u.getAuthorities())
			if(!user.getAuthorities().contains(existing.getAuthority()))
				u.removeAuthority(this.authorityRepository.find(existing.getAuthority()));
		
		// add new roles (if in dto, but not in the domain obj, then add to the domain obj)
		for(String newAuthority : user.getAuthorities())
			if(!u.hasAuthority(newAuthority))
				u.addAuthority(this.authorityRepository.find(newAuthority));
		
		u = this.userRepository.saveOrUpdate(u);
		return u.toDTO();
	}

	
	// TODO - this method should only be called by ROLE_ADMIN
	@Transactional
	public UserDTO updateUser(UserDTO user) {
		User u = this.userRepository.findById(user.getId());
		u.setUsername(user.getUsername());
		u.setName(user.getName());
		
		// Update the password ONLY if the password in the DTO isn't empty
		if(!"".equals(user.getPassword()))
			u.setPassword(user.getPassword());
				
		// reconcile the roles
		// remove old roles (if in current domain obj, but not in the DTO, then remove it)
		for(GrantedAuthority existing : u.getAuthorities())
			if(!user.getAuthorities().contains(existing.getAuthority()))
				u.removeAuthority(this.authorityRepository.find(existing.getAuthority()));
		
		// add new roles (if in dto, but not in the domain obj, then add to the domain obj)
		for(String newAuthority : user.getAuthorities())
			if(!u.hasAuthority(newAuthority))
				u.addAuthority(this.authorityRepository.find(newAuthority));
		
		u = this.userRepository.saveOrUpdate(u);
		return u.toDTO();
	}

	@Transactional(readOnly=true)
	public List<UserDTO> getUsers() {
		List<User> users = this.userRepository.getAllUsers();
		List<UserDTO> dtos = new ArrayList<UserDTO>();
		for(User user : users)
			dtos.add(user.toDTO());
		return dtos;
	}
	
	// TODO - only allow ROLE_ADMIN to do this
	@Transactional
	public void deleteUser(Long id) {
		User user = this.userRepository.findById(id);
		if(user != null)
			this.userRepository.deleteUser(user);
	}

	@Transactional(readOnly=true)
	public UserDTO getUser(Long id) {
		User user = this.userRepository.findById(id);
		return user.toDTO();
	}

	
}
